﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using Firecracker.Bootstrapper.Interception.Application;
using Firecracker.Bootstrapper.Interception.Intercepts;
using Mono.Cecil;

namespace Firecracker.Bootstrapper.Interception
{
  [Export]
  public class AssemblyProcessor
  {
    [ImportMany]
    public IEnumerable<IInjector> Injectors { get; set;}

    [Import]
    public IInterceptLocator Locator { get; set; }

    public void Process(AssemblyDefinition instrumentAssembly, AssemblyDefinition testAssembly)
    {
      Locator.PointTo(testAssembly);


      foreach (TypeDefinition type in instrumentAssembly.MainModule.Types)
      {
        if (type.Name != "<Module>")
        {
          Console.WriteLine("\tFound type: " + type.FullName);
          //Gets all methods of the current type
          foreach (MethodDefinition method in type.Methods)
          {
            Console.WriteLine("\t\t" + method);

            foreach (var instruction in method.Body.Instructions)
            {
              Console.WriteLine("\t\t\t" + instruction);
            }
          }
        }
      }

      foreach (TypeDefinition type in instrumentAssembly.MainModule.Types)
      {
        if (type.Name != "<Module>")
        {
          foreach (MethodDefinition method in type.Methods)
          {
            foreach (var instruction in method.Body.Instructions.ToList())
            {
              var def = new InstructionDefinition
                          {CallingMethod = method, CallingType = type, Instruction = instruction};
              foreach (var injector in Injectors.Where(x => x.ShouldApply(def)).ToList())
              {
                injector.Apply(def);
              }
            }
          }
        }
      }
      foreach (TypeDefinition type in instrumentAssembly.MainModule.Types)
      {
        if (type.Name != "<Module>")
        {
          Console.WriteLine("\tFound type: " + type.FullName);
          //Gets all methods of the current type
          foreach (MethodDefinition method in type.Methods)
          {
            Console.WriteLine("\t\t" + method);

            foreach (var instruction in method.Body.Instructions)
            {
              Console.WriteLine("\t\t\t" + instruction);
            }
          }
        }
      }
    }
  }
}
